home *** CD-ROM | disk | FTP | other *** search
- //==// // // /|| // //==== //==// //| //
- // // // // //|| // // // // //|| //
- //==// //==// //=|| // // // // // || //
- // // // // || // // // // // ||//
- // // // // || //==== //==== //==// // ||/
-
- /==== // // // /==== /| /|
- // // // // // //| //|
- ===\ // // // ===\ //|| //||
- // // \\ // // // ||// ||
- ====/ // \\ // ====/ // ||/ ||
-
- ───────────────────────────────────────────
- DISCLAIMER: This file is 100% guaranteed to
- exist. The author makes no claims to the
- existence or nonexistence of the reader.
- ───────────────────────────────────────────
- This space intentionally left blank.
- ───────────────────────────────────────────
- GREETS: Welcome home, Hellraiser! Hello to
- the rest of the PHALCON/SKISM crew: Count
- Zero, Demogorgon, Garbageheap, as well as
- everyone else I failed to mention.
- ───────────────────────────────────────────
-
- Dark Angel's Clumpy Virus Writing Guide
- ──── ─────── ────── ───── ─────── ─────
- "It's the cheesiest" - Kraft
-
- ──────────────────────────────────────
- INSTALLMENT IV: RESIDENT VIRII, PART I
- ──────────────────────────────────────
-
- Now that the topic of nonresident virii has been addressed, this series now
- turns to memory resident virii. This installment covers the theory behind
- this type of virus, although no code will be presented. With this
- knowledge in hand, you can boldly write memory resident virii confident
- that you are not fucking up too badly.
-
- ──────────
- INTERRUPTS
- ──────────
- DOS kindly provides us with a powerful method of enhancing itself, namely
- memory resident programs. Memory resident programs allow for the extention
- and alteration of the normal functioning of DOS. To understand how memory
- resident programs work, it is necessary to delve into the intricacies of
- the interrupt table. The interrupt table is located from memory location
- 0000:0000 to 0000:0400h (or 0040:0000), just below the BIOS information
- area. It consists of 256 double words, each representing a segment:offset
- pair. When an interrupt call is issued via an INT instruction, two things
- occur, in this order:
-
- 1) The flags are pushed onto the stack.
- 2) A far call is issued to the segment:offset located in the interrupt
- table.
-
- To return from an interrupt, an iret instruction is used. The iret
- instruction reverses the order of the int call. It performs a retf
- followed by a popf. This call/return procedure has an interesting
- sideeffect when considering interrupt handlers which return values in the
- flags register. Such handlers must directly manipulate the flags register
- saved in the stack rather than simply directly manipulating the register.
-
- The processor searches the interrupt table for the location to call. For
- example, when an interrupt 21h is called, the processor searches the
- interrupt table to find the address of the interrupt 21h handler. The
- segment of this pointer is 0000h and the offset is 21h*4, or 84h. In other
- words, the interrupt table is simply a consecutive chain of 256 pointers to
- interrupts, ranging from interrupt 0 to interrupt 255. To find a specific
- interrupt handler, load in a double word segment:offset pair from segment
- 0, offset (interrupt number)*4. The interrupt table is stored in standard
- Intel reverse double word format, i.e. the offset is stored first, followed
- by the segment.
-
- For a program to "capture" an interrupt, that is, redirect the interrupt,
- it must change the data in the interrupt table. This can be accomplished
- either by direct manipulation of the table or by a call to the appropriate
- DOS function. If the program manipulates the table directly, it should put
- this code between a CLI/STI pair, as issuing an interrupt by the processor
- while the table is half-altered could have dire consequences. Generally,
- direct manipulation is the preferable alternative, since some primitive
- programs such as FluShot+ trap the interrupt 21h call used to set the
- interrupt and will warn the user if any "unauthorised" programs try to
- change the handler.
-
- An interrupt handler is a piece of code which is executed when an interrupt
- is requested. The interrupt may either be requested by a program or may be
- requested by the processor. Interrupt 21h is an example of the former,
- while interrupt 8h is an example of the latter. The system BIOS supplies a
- portion of the interrupt handlers, with DOS and other programs supplying
- the rest. Generally, BIOS interrupts range from 0h to 1Fh, DOS interrupts
- range from 20h to 2Fh, and the rest is available for use by programs.
-
- When a program wishes to install its own code, it must consider several
- factors. First of all, is it supplanting or overlaying existing code, that
- is to say, is there already an interrupt handler present? Secondly, does
- the program wish to preserve the functioning of the old interrupt handler?
- For example, a program which "hooks" into the BIOS clock tick interrupt
- would definitely wish to preserve the old interrupt handler. Ignoring the
- presence of the old interrupt handler could lead to disastrous results,
- especially if previously-loaded resident programs captured the interrupt.
-
- A technique used in many interrupt handlers is called "chaining." With
- chaining, both the new and the old interrupt handlers are executed. There
- are two primary methods for chaining: preexecution and postexecution. With
- preexecution chaining, the old interrupt handler is called before the new
- one. This is accomplished via a pseudo-INT call consisting of a pushf
- followed by a call far ptr. The new interrupt handler is passed control
- when the old one terminates. Preexecution chaining is used when the new
- interrupt handler wishes to use the results of the old interrupt handler in
- deciding the appropriate action to take. Postexecution chaining is more
- straightforward, simply consisting of a jmp far ptr instruction. This
- method doesn't even require an iret instruction to be located in the new
- interrupt handler! When the jmp is executed, the new interrupt handler has
- completed its actions and control is passed to the old interrupt handler.
- This method is used primarily when a program wishes to intercept the
- interrupt call before DOS or BIOS gets a chance to process it.
-
- ────────────────────────────────────────
- AN INTRODUCTION TO DOS MEMORY ALLOCATION
- ────────────────────────────────────────
- Memory allocation is perhaps one of the most difficult concepts, certainly
- the hardest to implement, in DOS. The problem lies in the lack of official
- documentation by both Microsoft and IBM. Unfortunately, knowledge of the
- DOS memory manager is crucial in writing memory-resident virii.
-
- When a program asks DOS for more memory, the operating system carves out a
- chunk of memory from the pool of unallocated memory. Although this concept
- is simple enough to understand, it is necessary to delve deeper in order to
- have sufficient knowledge to write effective memory-resident virii. DOS
- creates memory control blocks (MCBs) to help itself keep track of these
- chunks of memory. MCBs are paragraph-sized areas of memory which are each
- devoted to keeping track of one particular area of allocated memory. When
- a program requests memory, one paragraph for the MCB is allocated in
- addition to the memory requested by the program. The MCB lies just in
- front of the memory it controls. Visually, a MCB and its memory looks
- like:
-
- ┌───────┬─────────────────────────────────────┐
- │ MCB 1 │ Chunk o' memory controlled by MCB 1 │
- └───────┴─────────────────────────────────────┘
-
- When a second section of memory is requested, another MCB is created just
- above the memory last allocated. Visually:
-
- ┌───────┬─────────┬───────┬─────────┐
- │ MCB 1 │ Chunk 1 │ MCB 2 │ Chunk 2 │
- └───────┴─────────┴───────┴─────────┘
-
- In other words, the MCBs are "stacked" one on top of the other. It is
- wasteful to deallocate MCB 1 before MCB 2, as holes in memory develop. The
- structure for the MCB is as follows:
-
- Offset Size Meaning
- ────── ─────── ───────
- 0 BYTE 'M' or 'Z'
- 1 WORD Process ID (PSP of block's owner)
- 3 WORD Size in paragraphs
- 5 3 BYTES Reserved (Unused)
- 8 8 BYTES DOS 4+ uses this. Yay.
-
- If the byte at offset 0 is 'M', then the MCB is not the end of the chain.
- The 'Z' denotes the end of the MCB chain. There can be more than one MCB
- chain present in memory at once and this "feature" is used by virii to go
- resident in high memory. The word at offset 1 is normally equal to the PSP
- of the MCB's owner. If it is 0, it means that the block is free and is
- available for use by programs. A value of 0008h in this field denotes DOS
- as the owner of the block. The value at offset 3 does NOT include the
- paragraph allocated for the MCB. It reflects the value passed to the DOS
- allocation functions. All fields located after the block size are pretty
- useless so you might as well ignore them.
-
- When a COM file is loaded, all available memory is allocated to it by DOS.
- When an EXE file is loaded, the amount of memory specified in the EXE
- header is allocated. There is both a minimum and maximum value in the
- header. Usually, the linker will set the maximum value to FFFFh
- paragraphs. If the program wishes to allocate memory, it must first shrink
- the main chunk of memory owned by the program to the minimum required.
- Otherwise, the pathetic attempt at memory allocation will fail miserably.
-
- Since programs normally are not supposed to manipulate MCBs directly, the
- DOS memory manager calls (48h - 4Ah) all return and accept values of the
- first program-usable memory paragraph, that is, the paragraph of memory
- immediately after the MCB. It is important to keep this in mind when
- writing MCB-manipulating code.
-
- ─────────────────────────
- METHODS OF GOING RESIDENT
- ─────────────────────────
- There are a variety of memory resident strategies. The first is the use of
- the traditional DOS interrupt TSR routines, either INT 27h or INT
- 21h/Function 31h. These routines are undesirable when writing virii,
- because they do not return control back to the program after execution.
- Additionally, they show up on "memory walkers" such as PMAP and MAPMEM.
- Even a doorknob can spot such a blatant viral presence.
-
- The traditional viral alternative to using the standard DOS interrupt is,
- of course, writing a new residency routine. Almost every modern virus uses
- a routine to "load high," that is, to load itself into the highest possible
- memory location. For example, in a 640K system, the virus would load
- itself just under the 640K but above the area reserved by DOS for program
- use. Although this is technically not the high memory area, it shall be
- referred to as such in the remainder of this file in order to add confusion
- and general chaos into this otherwise well-behaved file. Loading high can
- be easily accomplished through a series of interrupt calls for reallocation
- and allocation. The general method is:
-
- 1. Find the memory size
- 2. Shrink the program's memory to the total memory size - virus size
- 3. Allocate memory for the virus (this will be in the high memory area)
- 4. Change the program's MCB to the end of the chain (Mark it with 'Z')
- 5. Copy the virus to high memory
- 6. Save the old interrupt vectors if the virus wishes to chain vectors
- 7. Set the interrupt vectors to the appropriate locations in high memory
-
- When calculating memory sizes, remember that all sizes are in paragraphs.
- The MCB must also be considered, as it takes up one paragraph of memory.
- The advantage of this method is that it does not, as a rule, show up on
- memory walkers. However, the total system memory as shown by such programs
- as CHKDSK will decrease.
-
- A third alternative is no allocation at all. Some virii copy themselves to
- the memory just under 640K, but fail to allocate the memory. This can have
- disastrous consequences, as any program loaded by DOS can possibly use this
- memory. If it is corrupted, unpredictable results can occur. Although no
- memory loss is shown by CHKDSK, the possible chaos resulting from this
- method is clearly unacceptable. Some virii use memory known to be free.
- For example, the top of the interrupt table or parts of video memory all
- may be used with some assurance that the memory will not be corrupted.
- Once again, this technique is undesirable as it is extremely unstable.
-
- These techniques are by no means the only methods of residency. I have
- seen such bizarre methods as going resident in the DOS internal disk
- buffers. Where there's memory, there's a way.
-
- It is often desirable to know if the virus is already resident. The
- simplest method of doing this is to write a checking function in the
- interrupt handler code. For example, a call to interrupt 21h with the ax
- register set to 7823h might return a 4323h value in ax, signifying
- residency. When using this check, it is important to ensure that no
- possible conflicts with either other programs or DOS itself will occur.
- Another method, albeit a costly process in terms of both time and code
- length, is to check each segment in memory for the code indicating the
- presence of the virus. This method is, of course, undesirable, since it is
- far, far simpler to code a simple check via the interrupt handler. By
- using any type of check, the virus need not fear going resident twice,
- which would simply be a waste of memory.
-
- ─────────────
- WHY RESIDENT?
- ─────────────
- Memory resident virii have several distinct advantages over runtime virii.
- o Size
- Memory resident virii are often smaller than their runtime brethern as
- they do not need to include code to search for files to infect.
- o Effectiveness
- They are often more virulent, since even the DIR command can be
- "infected." Generally, the standard technique is to infect each file
- that is executed while the virus is resident.
- o Speed
- Runtime virii infect before a file is executed. A poorly written or
- large runtime virus will cause a noticible delay before execution
- easily spotted by users. Additionally, it causes inordinate disk
- activity which is detrimental to the lifespan of the virus.
- o Stealth
- The manipulation of interrupts allows for the implementation of
- stealth techniques, such as the hiding of changes in file lengths in
- directory listings and on-the-fly disinfection. Thus it is harder for
- the average user to detect the virus. Additionally, the crafty virus
- may even hide from CRC checks, thereby obliterating yet another anti-
- virus detection technique.
-
- ───────────────────────────────
- STRUCTURE OF THE RESIDENT VIRUS
- ───────────────────────────────
- With the preliminary information out of the way, the discussion can now
- shift to more virus-related, certainly more interesting topics. The
- structure of the memory resident virus is radically different from that of
- the runtime virus. It simply consists of a short stub used to determine if
- the virus is already resident. If it is not already in memory, the stuf
- loads it into memory through whichever method. Finally, the stub restores
- control to the host program. The rest of the code of the resident virus
- consists of interrupt handlers where the bulk of the work is done.
-
- The stub is the only portion of the virus which needs to have delta offset
- calculations. The interrupt handler ideally will exist at a location which
- will not require such mundane fixups. Once loaded, there should be no
- further use of the delta offset, as the location of the variables is
- preset. Since the resident virus code should originate at offset 0 of the
- memory block, originate the source code at offset 0. Do not include a jmp
- to the virus code in the original carrier file. When moving the virus to
- memory, simply move starting from [bp+startvirus] and the offsets should
- work out as they are in the source file. This simplifies (and shortens)
- the coding of the interrupt handlers.
-
- Several things must be considered in writing the interrupt handlers for a
- virus. First, the virus must preserve the registers. If the virus uses
- preexecution chaining, it must save the registers after the call to the
- original handler. If the virus uses postexecution chaining, it must
- restore the original registers of the interrupt call before the call to the
- original handler. Second, it is more difficult, though not impossible, to
- implement encryption with memory resident virii. The problem is that if
- the interrupt handler is encrypted, that interrupt handler cannot be called
- before the decryption function. This can be a major pain in the ass. The
- cheesy way out is to simply not include encryption. I prefer the cheesy
- way. The noncheesy readers out there might wish to have the memory
- simultaneously hold two copies of the virus, encrypt the unused copy, and
- use the encrypted copy as the write buffer. Of course, the virus would
- then take twice the amount of memory it would normally require. The use of
- encryption is a matter of personal choice and cheesiness. A sidebar to
- preservation of interrupt handlers: As noted earlier, the flags register is
- restored from the stack. It is important in preexecution chaining to save
- the new flags register onto the stack where the old flags register was
- stored.
-
- Another important factor to consider when writing interrupt handlers,
- especially those of BIOS interrupts, is DOS's lack of reentrance. This
- means that DOS functions cannot be executed while DOS is in the midst of
- processing an interrupt request. This is because DOS sets up the same
- stack pointer each time it is called, and calling the second DOS interrupt
- will cause the processing of one to overwrite the stack of the other,
- causing unpredictable, but often terminal, results. This applies
- regardless of which DOS interrupts are called, but it is especially true
- for interrupt 21h, since it is often tempting to use it from within an
- interrupt handler. Unless it is certain that DOS is not processing a
- previous request, do NOT use a DOS function in the interrupt handler. It
- is possible to use the "lower" interrupt 21h functions without fear of
- corrupting the stack, but they are basically the useless ones, performing
- functions easily handled by BIOS calls or direct hardware access. This
- entire discussion only applies to hooking non-DOS interrupts. With hooking
- DOS interrupts comes the assurance that DOS is not executing elsewhere,
- since it would then be corrupting its own stack, which would be a most
- unfortunate occurence indeed.
-
- The most common interrupt to hook is, naturally, interrupt 21h. Interrupt
- 21h is called by just about every DOS program. The usual strategy is for a
- virus to find potential files to infect by intercepting certain DOS calls.
- The primary functions to hook include the find first, find next, open, and
- execute commands. By cleverly using pre and postexecution chaining, a
- virus can easily find the file which was found, opened, or executed and
- infect it. The trick is simply finding the appropriate method to isolate
- the filename. Once that is done, the rest is essentially identical to the
- runtime virus.
-
- When calling interrupts hooked by the virus from the virus interrupt code,
- make sure that the virus does not trap this particular call, lest an
- infinite loop result. For example, if the execute function is trapped and
- the virus wishes, for some reason, to execute a particular file using this
- function, it should NOT use a simple "int 21h" to do the job. In cases
- such as this where the problem is unavoidable, simply simulate the
- interrupt call with a pushf/call combination.
-
- The basic structure of the interrupt handler is quite simple. The handler
- first screens the registers for either an identification call or for a
- trapped function such as execute. If it is not one of the above, the
- handler throws control back to the original interrupt handler. If it is an
- identification request, the handler simply sets the appropriate registers
- and returns to the calling program. Otherwise, the virus must decide if
- the request calls for pre or postexecution chaining. Regardless of which
- it uses, the virus must find the filename and use that information to
- infect. The filename may be found either through the use of registers as
- pointers or by searching thorugh certain data structures, such as FCBs.
- The infection routine is the same as that of nonresident virii, with the
- exception of the guidelines outlined in the previous few paragraphs.
-
- ──────────────
- WHAT'S TO COME
- ──────────────
- I apologise for the somewhat cryptic sentences used in the guide, but I'm a
- programmer, not a writer. My only suggestion is to read everything over
- until it makes sense. I decided to pack this issue of the guide with
- theory rather than code. In the next installment, I will present all the
- code necessary to write a memory-resident virus, along with some techniques
- which may be used. However, all the information needed to write a resident
- virii has been included in this installment; it is merely a matter of
- implementation. Have buckets o' fun!
-
-